home *** CD-ROM | disk | FTP | other *** search
- /* scanf - formatted input conversion Author: Patrick van Kleef */
-
- #define __SRC__
-
- /*
- * - added %f,%e,%g
- * - [scanset] implementation wrote into format string, which is
- * obviously a no-no. Changed that real quick.
- * - added [0-9] style scansets
- * ++jrb bammi@dsrgsun.ces.cwru.edu
- *
- * 12/10/88 minor bugfix to accept floating #'s of the for .nnnn
- * ++jrb
- */
-
-
- #include <stdio.h>
-
-
- int scanf (format, args)
- CONST char *format;
- int args;
- {
- return _doscanf (0, stdin, format, &args);
- }
-
-
-
- int fscanf (fp, format, args)
- FILE *fp;
- CONST char *format;
- int args;
- {
- return _doscanf (0, fp, format, &args);
- }
-
-
- int sscanf (string, format, args)
- CONST char *string; /* source of data */
- CONST char *format; /* control string */
- int args;
- {
- return _doscanf (1, string, format, &args);
- }
-
- union ptr_union {
- char *chr_p;
- unsigned int *uint_p;
- unsigned long *ulong_p;
- #ifndef __NO_FLOATS__
- float *float_p;
- double *double_p;
- #endif
- };
-
- static int ic; /* the current character */
- static char *rnc_arg; /* the string or the filepointer */
- static int rnc_code; /* 1 = read from string, else from FILE */
-
- /* get the next character */
-
- static void rnc ()
- {
- if (rnc_code) {
- if (!(ic = *rnc_arg++))
- ic = EOF;
- } else
- ic = getc ((FILE *) rnc_arg);
- }
-
- /*
- * unget the current character
- */
-
- static void ugc ()
- {
-
- if (rnc_code)
- --rnc_arg;
- else
- ungetc (ic, (FILE *)rnc_arg);
- }
-
- /* [01234] style scanset */
- static int scn1index(ch, string, endmarker)
- char ch;
- char *string, *endmarker;
- {
- while (*string++ != ch)
- if (string >= endmarker)
- return 0;
- return 1;
- }
-
- static int scnindex(ch, string, endmarker)
- char ch;
- char *string, *endmarker;
- {
- if(((endmarker - string) == 3) && (string[1] == '-'))
- /* [0-9] style scanset */
- return ((string[0] <= ch) && (ch <= string[2]));
- else
- return scn1index(ch, string, endmarker);
- }
-
- /*
- * this is cheaper than iswhite from <ctype.h>
- */
-
- static int iswhite (ch)
- int ch;
- {
- return (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
- }
-
- static int isdigit (ch)
- int ch;
- {
- return (ch >= '0' && ch <= '9');
- }
-
- static int __tolower (ch)
- int ch;
- {
- if (ch >= 'A' && ch <= 'Z')
- ch = ch + 'a' - 'A';
-
- return ch;
- }
-
- #ifndef __NO_FLOATS__
- #ifdef __GNUC__
- /* eval f * 10**p */
- static double _fraise(f, p)
- double f;
- int p;
- {
- if(p > 0)
- while(p--)
- f *= 10.0;
- else
- while(p++)
- f /= 10.0;
- return f;
- }
- #endif
- #endif
-
- /*
- * the routine that does the job
- */
-
- int _doscanf (code, funcarg, format, argp)
- int code; /* function to get a character */
- char *funcarg; /* an argument for the function */
- char *format; /* the format control string */
- union ptr_union *argp; /* our argument list */
- {
- int done = 0; /* number of items done */
- int base; /* conversion base */
- long val; /* an integer value */
- int sign; /* sign flag */
- int do_assign; /* assignment suppression flag */
- unsigned width; /* width of field */
- int widflag; /* width was specified */
- int longflag; /* true if long */
- int done_some; /* true if we have seen some data */
- int reverse; /* reverse the checking in [...] */
- char *endbracket; /* position of the ] in format string */
- #ifndef __NO_FLOATS__
- #ifdef __GNUC__
- double fval; /* a double value */
- #endif
- #endif
-
-
- rnc_arg = funcarg;
- rnc_code = code;
-
- rnc (); /* read the next character */
-
- if (ic == EOF) {
- done = EOF;
- goto quit;
- }
-
- while (1) {
- while (iswhite (*format))
- ++format; /* skip whitespace */
- if (!*format)
- goto all_done; /* end of format */
- if (ic < 0)
- goto quit; /* seen an error */
- if (*format != '%') {
- while (iswhite (ic))
- rnc ();
- if (ic != *format)
- goto all_done;
- ++format;
- rnc ();
- ++done;
- continue;
- }
- ++format;
- do_assign = 1;
- if (*format == '*') {
- ++format;
- do_assign = 0;
- }
- if (isdigit (*format)) {
- widflag = 1;
- for (width = 0; isdigit (*format);)
- width = width * 10 + *format++ - '0';
- } else
- widflag = 0; /* no width spec */
- if (longflag = (__tolower (*format) == 'l'))
- ++format;
- if (*format != 'c')
- while (iswhite (ic))
- rnc ();
- done_some = 0; /* nothing yet */
- switch (*format) {
- case 'o':
- base = 8;
- goto decimal;
- case 'u':
- case 'd':
- base = 10;
- goto decimal;
- case 'x':
- base = 16;
- if (((!widflag) || width >= 2) && ic == '0') {
- rnc ();
- if (__tolower (ic) == 'x') {
- width -= 2;
- done_some = 1;
- rnc ();
- } else {
- ugc ();
- ic = '0';
- }
- }
- decimal:
- val = 0L; /* our result value */
- sign = 0; /* assume positive */
- if (!widflag)
- width = 0xffff; /* very wide */
- if (width && ic == '+')
- rnc ();
- else if (width && ic == '-') {
- sign = 1;
- rnc ();
- }
- while (width--) {
- if (isdigit (ic) && ic - '0' < base)
- ic -= '0';
- else if (base == 16 && __tolower (ic) >= 'a' && __tolower (ic) <= 'f')
- ic = 10 + __tolower (ic) - 'a';
- else
- break;
- val = val * base + ic;
- rnc ();
- done_some = 1;
- }
- if (do_assign) {
- if (sign)
- val = -val;
- if (longflag)
- *(argp++)->ulong_p = (unsigned long) val;
- else
- *(argp++)->uint_p = (unsigned) val;
- }
- if (done_some)
- ++done;
- else
- goto all_done;
- break;
- case 'c':
- if (!widflag)
- width = 1;
- while (width-- && ic >= 0) {
- if (do_assign)
- *(argp)->chr_p++ = (char) ic;
- rnc ();
- done_some = 1;
- }
- if (do_assign)
- argp++; /* done with this one */
- if (done_some)
- ++done;
- break;
- case 's':
- if (!widflag)
- width = 0xffff;
- while (width-- && !iswhite (ic) && ic > 0) {
- if (do_assign)
- *(argp)->chr_p++ = (char) ic;
- rnc ();
- done_some = 1;
- }
- if (do_assign) /* terminate the string */
- *(argp++)->chr_p = '\0';
- if (done_some)
- ++done;
- else
- goto all_done;
- break;
-
- #ifndef __NO_FLOATS__
- #ifdef __GNUC__
- case 'e':
- case 'f':
- case 'g':
- fval = 0.0; /* our result value */
- sign = 0; /* assume positive */
- if (!widflag)
- width = 0xffff; /* very wide */
- if (width && ic == '+')
- rnc ();
- else if (width && ic == '-') {
- sign = 1;
- rnc ();
- }
- while (width && isdigit(ic)) {
- width--;
- fval = fval * 10.0 + (ic - '0');
- rnc ();
- done_some = 1;
- }
- if(ic == '.')
- {
- double factor = 1.0/10.0;
- rnc ();
- while (--width && isdigit(ic))
- {
- fval = fval + ((ic - '0') * factor);
- factor = factor/10.0;
- done_some = 1;
- rnc();
- }
- }
- if(sign)
- fval = -fval;
- sign = 0;
- if(((ic == 'E') || (ic == 'e')) && done_some)
- {
- int pow = 0;
- rnc ();
- if((ic == '+') || (ic == '-'))
- {
- if(ic == '-') sign = 1;
- width--;
- rnc();
- }
-
- while(--width && isdigit(ic))
- {
- pow = pow * 10 + (ic -'0');
- rnc();
- }
- fval = _fraise(fval, (sign == 1)? -pow : pow);
- }
- if (do_assign) {
- if (longflag)
- *(argp++)->double_p = fval;
- else
- *(argp++)->float_p = (float) fval;
- }
- if (done_some)
- ++done;
- else
- goto all_done;
- break;
- #endif /* __GNUC__ */
- #endif /* __NO_FLOATS__ */
-
- case '[':
- if (!widflag)
- width = 0xffff;
-
- if ( *(++format) == '^' ) {
- reverse = 1;
- format++;
- } else
- reverse = 0;
-
- endbracket = format;
- while ( *endbracket != ']' && *endbracket != '\0')
- endbracket++;
-
- if (!*endbracket)
- goto quit;
-
- while (width-- && !iswhite (ic) && ic > 0 &&
- (scnindex(ic, format, endbracket) ^ reverse)) {
- if (do_assign)
- *(argp)->chr_p++ = (char) ic;
- rnc ();
- done_some = 1;
- }
-
- if (do_assign) /* terminate the string */
- *(argp++)->chr_p = '\0';
- if (done_some)
- ++done;
- else
- goto all_done;
- break;
- } /* end switch */
- ++format;
- }
- all_done:
- if (ic >= 0)
- ugc (); /* restore the character */
- quit:
- return done;
- }
-
- #if 0
- /* TEST ONLY */
- main()
- {
- int i, n;
- float x;
- char name[50];
-
- n = scanf("%d%f%s", &i, &x, name);
- printf("n = %d i = %d x = %f name = :%s:\n", n, i, x, name);
- /* input: 54.32E-1 thompson */
- /* output: n = 3 i = 25 x = 5.432000 name = :thompson: */
-
- n = scanf("%2d%f%*d %[0-9]", &i, &x, name);
- printf("n = %d i = %d x = %f name = :%s:\n", n, i, x, name);
- /* input: 56789 0123 56a72 */
- /* output: n = 4 i = 56 x = 789.000000 name = :56: */
-
- n = scanf("%s", name);
- printf("n = %d name = :%s:\n", n, name);
- /* output: n = 1 name = :a72: */
-
- n = scanf("%2d%f%*d %[0123456789]", &i, &x, name);
- printf("n = %d i = %d x = %f name = :%s:\n", n, i, x, name);
- /* input: 56789 0123 56a72 */
- /* output: n = 4 i = 56 x = 789.000000 name = :56: */
- /* 'a72' left over */
-
- n = scanf("%s", name);
- printf("n = %d name = :%s:\n", n, name);
- /* output: n = 1 name = :a72: */
- }
- #endif /* test only */
-